package com.dynabook.ems.aop;

import com.dynabook.ems.model.vo.UserLoginVO;
import com.dynabook.ems.model.vo.UserRoleVO;
import com.dynabook.ems.service.RolesService;
import com.dynabook.ems.service.UsersService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;

/**
 * Cookie 处理切面
 * 支持同域名不同端口的cookie获取和用户登录信息设置
 */
@Aspect
@Component
@Slf4j
@Order(0) // 添加这行，确保CookieInterceptor先执行
public class CookieInterceptor {

    @Resource
    private UsersService usersService;

    private static final String AUTH_COOKIE_NAME = "TESTLINK_USER_AUTH_COOKIE";
    private static final String USER_SESSION_KEY = "user_login";
//    private static final String TEST_AUTH_TOKEN = "16d4bd4b79e9310fca17b423863baec6f8eedb3f8a82455f9ad789539210d232";
    private static final String TEST_AUTH_TOKEN = "a962d816f560d47562b5777b6d87d2f290aeff771cc7f0447a1f656765d742d8";
//    private static final String TEST_AUTH_TOKEN = "838346a4693810f8ce2e8802cd36c841b7896b280a7f82bed34463f0d3cf77d8";

    // 通过配置文件配置允许的域名
    @Value("${app.auth.allowed-domain:}")
    private String allowedDomain;

    // 通过配置文件配置前端端口
    @Value("${app.auth.frontend-port:8087}")
    private String frontendPort;

    // 通过配置文件配置后端端口
    @Value("${app.auth.backend-port:81}")
    private String backendPort;
    
    // 是否为测试环境
    @Value("${spring.is_test:false}")
    private boolean isTestEnvironment;

    @Resource
    private RolesService rolesService;

    /**
     * 拦截所有控制器方法，处理 cookie
     */
    @Around("execution(* com.dynabook.ems.controller.*.*(..))")
    public Object processCookie(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取请求上下文
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes != null) {
            HttpServletRequest request = attributes.getRequest();
            processCookieFromRequest(request);
        }

        // 执行原方法
        return joinPoint.proceed();
    }

    /**
     * 从请求中处理 cookie
     */
    private void processCookieFromRequest(HttpServletRequest request) {
        try {
            // 测试环境下，直接使用固定的测试token
            if (isTestEnvironment) {
                log.info("运行在测试环境中，使用测试用户认证Token");
                processAuthToken(TEST_AUTH_TOKEN, request);
                return;
            }
            
            // 以下是生产环境的逻辑
            // 优先从Header中获取token（推荐方案）
            String authToken = getAuthTokenFromHeader(request);
            if (StringUtils.hasText(authToken)) {
                processAuthToken(authToken, request);
                return;
            }

            // 从Cookie中获取
            String cookieValue = getAuthCookieValue(request);
            if (StringUtils.hasText(cookieValue)) {
                processAuthToken(cookieValue, request);
                return;
            }

            log.debug("未找到认证信息，请求来源: {}:{}", request.getServerName(), request.getServerPort());

        } catch (Exception e) {
            log.error("处理认证信息时发生错误: {}", e.getMessage(), e);
        }
    }

    /**
     * 从请求头中获取认证token
     */
    private String getAuthTokenFromHeader(HttpServletRequest request) {
        // 常见的认证header名称
        String[] headerNames = {
                "Authorization",
                "X-Auth-Token",
                "X-User-Token",
                "TESTLINK-USER-AUTH-TOKEN"
        };

        for (String headerName : headerNames) {
            String headerValue = request.getHeader(headerName);
            if (StringUtils.hasText(headerValue)) {
                // 处理Bearer类型的token
                if (headerValue.startsWith("Bearer ")) {
                    return headerValue.substring(7);
                }
                log.debug("从Header获取到认证token: {}", headerName);
                return headerValue;
            }
        }
        return null;
    }

    /**
     * 从Cookie中获取认证token
     */
    private String getAuthCookieValue(HttpServletRequest request) {
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if (AUTH_COOKIE_NAME.equals(cookie.getName())) {
                    // 验证请求是否来自目标域名
                    if (isValidDomain(request)) {
                        log.debug("从Cookie获取到认证token: {}", cookie.getValue());
                        return cookie.getValue();
                    } else {
                        log.warn("请求来源域名不匹配: {}, 期望: {}",
                                request.getServerName(), allowedDomain);
                    }
                }
            }
        } else {
            log.debug("请求中未找到任何Cookie");
        }
        return null;
    }

    /**
     * 验证请求域名是否有效
     */
    private boolean isValidDomain(HttpServletRequest request) {
        String serverName = request.getServerName();

        // 如果没有配置允许的域名，则允许所有请求
        if (!StringUtils.hasText(allowedDomain)) {
            log.debug("未配置允许的域名，允许所有请求");
            return true;
        }

        boolean isValid = allowedDomain.equals(serverName);
        if (!isValid) {
            log.warn("请求来源域名不匹配: {}, 期望: {}", serverName, allowedDomain);
        }

        return isValid;
    }

    /**
     * 处理认证token
     */
    private void processAuthToken(String authToken, HttpServletRequest request) {
        try {
            // 测试环境下，直接创建测试用户
            if (isTestEnvironment && TEST_AUTH_TOKEN.equals(authToken)) {
                UserLoginVO testUser = usersService.getLoginUser(TEST_AUTH_TOKEN);

                UserRoleVO roleByUserId = rolesService.getRoleByUserId(testUser.getUserNum());
                if(roleByUserId != null) {
                    testUser.setRoleId(roleByUserId.getRoleId());
                    testUser.setDescription(roleByUserId.getDescription());
                    testUser.setNotes(roleByUserId.getNotes());
                }
                // 设置到 session 中
                request.getSession().setAttribute(USER_SESSION_KEY, testUser);
                log.info("测试环境：已设置测试用户登录信息到session: {}", testUser);
                return;
            }
            
            // 生产环境或其他token情况
            UserLoginVO userLoginVO = usersService.getLoginUser(authToken);
            UserRoleVO roleByUserId = rolesService.getRoleByUserId(userLoginVO.getUserNum());
            if(roleByUserId != null) {
                userLoginVO.setRoleId(roleByUserId.getRoleId());
                userLoginVO.setDescription(roleByUserId.getDescription());
                userLoginVO.setNotes(roleByUserId.getNotes());
            }
            if (userLoginVO != null) {
                // 设置到 session 中
                request.getSession().setAttribute(USER_SESSION_KEY, userLoginVO);
                log.debug("用户登录信息已设置到session: {}", userLoginVO);
            } else {
                log.debug("根据认证token未找到用户信息");
            }
        } catch (Exception e) {
            log.error("获取用户登录信息时发生错误: {}", e.getMessage(), e);
        }
    }
}